<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="lib/cesium/Cesium.js"></script>
    <style>
        @import url(./lib/cesium/widgets.css);

        html,
        body,

        #mainContainer {
            margin: 0;
            padding: 0;
            overflow: hidden;
            height: 1000px;
        }

        #cesiumContainer {
            margin: 0;
            padding: 0;
            overflow: auto;
        }
    </style>
</head>
<body>
<div id="mainContainer">
    <!---->
    <div id="title"></div>
    <!---->
    <div id="logContainer"></div>
    <!--    -->
    <div id="cesiumContainer"></div>
</div>

<script type="module">
    import { LCCRender } from './sdk/LCC-Web-0.5.1/lcc-0.5.1.js'
    import { CesiumAppConfig } from './js/CesiumAppConfig.js'
    import { JCLCCRenderer } from './js/JCLCCRenderer.js'

    function printLog(content){
        const item = document.getElementById('logContainer');
        item.innerHTML = item.innerHTML + content + "<br/>";
    }



    // 获取查询参数
    function getQueryParams() {
        // console.log('right-2-1 getQueryParams() location' + window.location);
        const search = window.location.search; // 获取 URL 中的查询字符串（例如："?name=Alice&age=30"）
        console.log('right-2-1 getQueryParams() search:' + window.location.search);
        const params = new URLSearchParams(search);

        // // 获取单个参数
        // const name = params.get('name'); // 例如："Alice"
        // const age = params.get('age');   // 例如："30"

        // 获取所有参数（转为对象）
        const paramObject = Object.fromEntries(params.entries());
        console.log("paramObject:"+ paramObject); // 例如：{ name: "Alice", age: "30" }

        // console.log("paramObject.requestUrl2:"+ paramObject['requestUrl']);
        return paramObject;
    }

    // 解析获取的查询参数，获取其中的请求路径(加载的lcc的路径)
    function getRequestUrl(){
        const currentPage = "threeDGSLCCForCesiumRightPage.html";
        console.log('getRequestUrl() currentPage:' + currentPage);
        const queryParams = getQueryParams();
        // 获取指定的参数
        const requestUrl = queryParams['requestUrl'];
        console.log('getRequestUrl() requestUrl:' + requestUrl);
        return requestUrl;
    }

    // 获取Cesium的token信息
    function getCesiumToken(){
        console.log('getCesiumToken() token:' + CesiumAppConfig.getToken());
        // const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI4ODUyNmNkNy1lMWI4LTQyNWMtODdjNi1iMmU1NWEwZTMxNmMiLCJpZCI6MzA2MjUyLCJpYXQiOjE3NDgyMzE2MTh9.rYKtbC3bpT7IvG0pTDIbzXSWKxHLgSpbD_NnaW0HZM8';
        const token = CesiumAppConfig.getToken();
        console.log('getCesiumToken() token:' + token);
        return token;
    }

    function createViewer(containerId){
        const viewer = new Cesium.Viewer(containerId, {
            orderIndependentTranslucency: false, // Close order-independent rendering
            useDefaultRenderLoop: true,
            resolutionScale: window.devicePixelRatio,
            contextOptions: {
                webgl2: true, // 强制使用 WebGL 2.0
                requestWebgl2: true
            }
        });

        viewer.scene.debugShowFramesPerSecond = true;
        return viewer
    }

    function initializeCesium(){
        // Maybe you need to create an access token of your own.  https://cesium.com/learn/ion/cesium-ion-access-tokens/
        Cesium.Ion.defaultAccessToken = getCesiumToken();
        // 后续设置
        const obj = [6378137.0, 6378137.0, 6356752.3142451793];
        Cesium.Ellipsoid.WGS84 = Object.freeze(
            new Cesium.Ellipsoid(obj[0], obj[1], obj[2])
        );
    }

    function initCesiumAndCreateViewer(containerId){
        initializeCesium();
        const viewer = createViewer(containerId);
        console.log('initCesiumAndCreateViewer() viewer:' + viewer);
        return viewer;
    }


    // 全局对象
    class GlobalObject{
        constructor() {
            // 键盘控制类，界面退出时要释放的
            this.keyboardHandler = undefined;
        }

        setKeyboardHandler(item){
            this.keyboardHandler = item;
        }

        getKeyboardHandler(){
            return this.keyboardHandler;
        }
    }


    // 处理键盘按键控制，键盘相关按键在地图上操作
    //const keyboardHandler = defineKeyboardHandler(viewer);
    // 不再需要时释放
    //keyboardHandler.dispose();
    function defineKeyboardHandler(viewer) {
        class KeyboardHandler {
            constructor() {
                // 相机控制状态
                this.flags = {
                    moveForward: false, moveBackward: false, moveLeft: false, moveRight: false,
                    moveUp: false, moveDown: false,
                    lookUp: false, lookDown: false, lookLeft: false, lookRight: false,
                    twistLeft: false, twistRight: false,
                    zoomIn: false, zoomOut: false
                };

                // 键盘映射表（使用Map提高查找效率）
                this.keyMap = new Map([
                    // 相机位置控制
                    [87, 'moveForward'], [83, 'moveBackward'], [68, 'moveRight'],
                    [65, 'moveLeft'], [81, 'moveUp'], [69, 'moveDown'],
                    // 相机姿态控制
                    [38, 'lookUp'], [40, 'lookDown'], [37, 'lookLeft'],
                    [39, 'lookRight'], [96, 'twistLeft'], [110, 'twistRight'],
                    // 缩放控制
                    [107, 'zoomIn'], [109, 'zoomOut']
                ]);

                this.isRenderingEnabled = false;
                this._tickRemoveCallback = null;
                this._viewer = null;

                // 绑定事件处理函数以确保 this 的正确指向
                this.handleKeyDown = this.handleKeyDown.bind(this);
                this.handleKeyUp = this.handleKeyUp.bind(this);
            }

            // 初始化键盘监听
            init(_viewer) {
                console.log("KeyboardHandler.init() 初始化键盘监听...");
                this._viewer = _viewer;

                // 全局键盘处理(如果有多个区域都要键盘处理，这边该怎么做)
                document.addEventListener('keydown', this.handleKeyDown);
                document.addEventListener('keyup', this.handleKeyUp);

                console.log("KeyboardHandler.init() 结束键盘监听...");
            }

            // 键盘按下处理
            handleKeyDown(event) {
                const flagName = this.keyMap.get(event.keyCode);
                if (flagName) {
                    this.flags[flagName] = true;
                    this._enableRenderLoop(); // 按下任意键时启用 onTick
                    event.preventDefault(); // 防止按键默认行为
                }
            }

            // 键盘释放处理
            handleKeyUp(event) {
                const flagName = this.keyMap.get(event.keyCode);
                if (flagName) {
                    this.flags[flagName] = false;
                    this._disableRenderLoopIfNoKeysPressed(); // 松开后检查是否还有按键按下
                    event.preventDefault();
                }
            }

            // 渲染更新
            render(_viewer) {
                console.log("render() begin...");
                const camera = _viewer.camera;
                const ellipsoid = _viewer.scene.globe.ellipsoid;
                const cartographic = ellipsoid.cartesianToCartographic(camera.position);
                const cameraHeight = cartographic.height;

                // 根据相机高度动态调整移动速度
                const moveRate = cameraHeight / 100.0;
                const zoomRate = cameraHeight / 2;

                // 位置移动
                if (this.flags.moveForward) camera.moveForward(moveRate);
                if (this.flags.moveBackward) camera.moveBackward(moveRate);
                if (this.flags.moveLeft) camera.moveLeft(moveRate);
                if (this.flags.moveRight) camera.moveRight(moveRate);
                if (this.flags.moveUp) camera.moveUp(moveRate);
                if (this.flags.moveDown) camera.moveDown(moveRate);

                // 姿态调整
                if (this.flags.lookUp) camera.lookUp();
                if (this.flags.lookDown) camera.lookDown();
                if (this.flags.lookLeft) camera.lookLeft();
                if (this.flags.lookRight) camera.lookRight();
                if (this.flags.twistLeft) camera.twistLeft();
                if (this.flags.twistRight) camera.twistRight();

                // 缩放控制
                if (this.flags.zoomIn) camera.zoomIn(zoomRate);
                if (this.flags.zoomOut) camera.zoomOut(zoomRate);
            }

            _enableRenderLoop() {
                if (!this.isRenderingEnabled) {
                    const self = this;
                    this._tickRemoveCallback = this._viewer.clock.onTick.addEventListener(() => {
                        this.render(self._viewer);
                    });
                    this.isRenderingEnabled = true;
                }
            }

            // 判断是否有任何按键仍处于按下状态
            _areAnyKeysPressed() {
                return Object.values(this.flags).some((flag) => flag);
            }

            // 如果没有按键按下，则禁用渲染循环
            _disableRenderLoopIfNoKeysPressed() {
                if (this.isRenderingEnabled && !this._areAnyKeysPressed()) {
                    if (this._tickRemoveCallback) {
                        this._tickRemoveCallback(); // 移除 tick 监听器
                        this._tickRemoveCallback = null;
                    }
                    this.isRenderingEnabled = false;
                }
            }

            // 外部清理方法
            dispose() {
                console.log("KeyboardHandler.dispose() 释放键盘监听...");
                try {
                    document.removeEventListener('keydown', this.handleKeyDown);
                    document.removeEventListener('keyup', this.handleKeyUp);

                    if (this._tickRemoveCallback) {
                        this._tickRemoveCallback();
                        this._tickRemoveCallback = null;
                    }

                    this._viewer = null;
                } catch (error) {
                    console.error('Error disposing event listeners:', error);
                }
            }
        }
        // 上面是定义类，下面是厨师话和返回
        const keyboardHandler = new KeyboardHandler();
        keyboardHandler.init(viewer);

        return {
            dispose: () => {
                keyboardHandler.dispose();
            }
        };
    }

    function executeLoad(){
        // 获取请求参数
        let lccPath = getRequestUrl();
        console.log('executeLoad() lccPath:' + lccPath);
        console.log('Cesium.VERSION:' + Cesium.VERSION);
        // lccPath = "http://192.168.2.69:5502/example/data/3dGS/常州园区-202505261447/常州园区东半区/meta.lcc";
        // console.error('executeLoad() reset lccPath:' + lccPath);
        const containerId = 'cesiumContainer';
        const viewer = initCesiumAndCreateViewer(containerId);
        // add new

        loadLcc(lccPath,viewer);
    }

    // lccDataPath:加载lcc时请求的类
    function loadLcc(lccDataPath,viewer){
        console.log("loadLcc() lccDataPath:",lccDataPath)
        // 这段默认加上
        // 创建一个局部东北天坐标系（ENU）到地心固定坐标系（ECEF）的变换矩阵
        // 1:坐标转换
        // 2:创建变换矩阵
        const m1 = Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(114.0592, 22.5429, 10));

        const lccObject = LCCRender.load({
            camera: viewer.camera,
            scene: viewer.scene,
            dataPath: lccDataPath,
            renderLib: Cesium,
            modelMatrix: m1, // Init matrix
            canvas: viewer.scene.canvas,
            useEnv: false
        }, (mesh) => {
            //加载成功后回调的代码
            console.log("模型加载完成,mesh:", mesh);
            // 获取LCC模型的基准点坐标, WGS84笛卡尔坐标。可用于飞行.Cesium特有。
            const cartesian = lccObject.getTranslation();
            console.log("lcc 加载成功，cartesian: ", cartesian);


            // 这段代码的作用是在 Cesium 创建的三维地球场景中，指定的cartesian位置处添加一个大小为 2 像素的红色点标记。
            // 这种点标记通常用于表示地理位置、兴趣点或数据可视化中的特定点位。
            const point = {
                position: cartesian,
                point: { pixelSize: 2, color: Cesium.Color.RED }
            }
            const entity = viewer.entities.add(point);
            // 飞到指定位置
            viewer.flyTo(entity);

            //lcc加载成功，设置键盘控制事件
            {
                // 定义全局键盘处理类
                const keyboardHandler = defineKeyboardHandler(viewer);

                window.globalObject.setKeyboardHandler(keyboardHandler);
            }

            // executeRenderTest(lccObject);

            JCLCCRenderer.executeRenderer(lccObject);

        }, (percent) => {
            // 正在加载时候回调的代码(根据加载进度不断变化)
            console.log("Lcc object loading: " + (percent * 100).toFixed(1) + "%");
        }, () => {
            // 加载失败后回调的代码
            console.log("Lcc object loading failure");
            printLog("加载LCC失败...");
        });
        // 执行测试方法
        // executeRenderTest(lccObject);
    }

    //测试方法
    function executeRenderTest(object){
        console.log("executeRenderTest() 渲染测试...");

        // 全量渲染
        function executeRenderAll(lccObject){
            const maxSplats = 9000000;
            // const maxSplats = 3000000;
            lccObject.setMaxSplats(maxSplats);
            console.log("executeRenderAll()--全量渲染 maxSplats:",maxSplats);
            printLog("全量渲染,maxSplats: " + maxSplats)
        }

        // 根据LOD策略渲染
        function executeRenderByLod(lccObject){
            console.log("executeRenderByLoad()--load渲染 ");

            {
                // 开启空地一体化Lod策略
                // const maxSplats = 9000000;
                // lccObject.setMaxSplats(maxSplats);
                lccObject.setLodAutoLevelUp(true);
                // printLog("开启空地一体化Lod策略");
                console.error("开启空地一体化Lod策略");
                // 关闭空地一体化Lod策略
                // lccObject.setLodAutoLevelUp(false);
                // printLog("关闭空地一体化Lod策略");
            }

        }

        function executeRenderByLoadSelfDefine(lccObject){
            console.log("executeRenderByLoadSelfDefine()--自定义load策略 ");
        }

        function otherTest(lccObject){
            //查询当前LCC模型是否含有球谐数据，返回布尔值(如果有，可以考虑使用球谐数据进行光照计算)
            const ret = lccObject.hasShcoef();
            console.error("otherTest() hasShcoef() ret:" + ret);


            lccObject.setMaxSplats(2000000);
            // 这边获取的是 undefined (我这边是0.5.1版本相关代码)(相关代码必须在回调成功后代码执行)(因为是异步调用模式)
            const lodInfos = lccObject.getLodInfos();
            console.error("otherTest() getLodInfos() lodInfos:" + lodInfos);
        }

        // executeRenderAll(object);
        executeRenderByLod(object);
        // executeRenderByLoadSelfDefine(object);


        otherTest(object);

    }






    function executePageLoad(){
        window.globalObject = new GlobalObject();
        executeLoad();
    }

    function executePageUnload(){
        console.log('executePageUnload()');
        // 执行相关释放操作
        if (window.globalObject) {
            console.log('executePageUnload()--1');
            if(window.globalObject.getKeyboardRoamingController){
                const keyboardRoamingController = window.globalObject.getKeyboardRoamingController();
                if (keyboardRoamingController && keyboardRoamingController.dispose) {
                    console.log('executePageUnload()--2');
                    keyboardRoamingController.dispose();
                }
            }

            if(window.globalObject.getEventAPI){
                const eventAPI = window.globalObject.getEventAPI();
                if (eventAPI && eventAPI.dispose) {
                    console.log('executePageUnload()--eventAPI dispose()');
                    eventAPI.dispose();
                }
            }

        }
    }


    function pageExecute(){
        console.log('pageExecute()');

        window.addEventListener('DOMContentLoaded', () => {
            console.log('页面加载完成');
            executePageLoad();
        });

        // 测试代码块
        {
            // testPageUnload();
        }

        window.addEventListener('unload', () => {
            // executePageUnload();
        });
    }

    function testPageUnload(){
        let timeout = 1000 * 10;

        console.log("testPageUnload() 页面卸载测试，timeout:" + timeout);
        setTimeout(function () {
                executePageUnload();
            },
            timeout);
    }
    pageExecute();


</script>
</body>
</html>